package sc.digital.human;

import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Objects;

public class Tsn {
    private static final Logger logger = LoggerFactory.getLogger(Tsn.class);
    private static final String[] SEP_TEXT = {"\n", "。", "，"};
    private static final int SEP_LENGTH = 60;
    private final OkHttpClient httpClient = new OkHttpClient.Builder().build();

    public Tsn() {
    }

    public static String urlEncoder(String text) {
        if (text.length() > SEP_LENGTH) {
            for (String sep : SEP_TEXT) {
                text = text.split(sep)[0];
                if (text.length() <= SEP_LENGTH) {
                    return text;
                }
            }
            text = text.substring(0, SEP_LENGTH);
        }
        try {
            return URLEncoder.encode(URLEncoder.encode(text, "UTF-8"), "UTF-8");
        } catch (Exception e) {
            return text;
        }
    }

    /**
     * 语音合成
     *
     * @param token    Token
     * @param text     文字
     * @param per      声音
     * @param callback 回调
     */
    public void tts(Token token, String text, Per per, Callback callback) {
        token.refresh((credentials) -> {
            if (credentials == null) {
                callback.tts(null);
            } else {
                this.httpClient.newCall(new Request.Builder()
                        .url(String.format(Config.TTS_URL, urlEncoder(text), per.key, Aue.PCM16.key, credentials.access_token))
                        .build()).enqueue(new okhttp3.Callback() {
                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        if (logger.isInfoEnabled()) {
                            logger.info("语音合成：{}", response);
                        }
                        if (!response.isSuccessful() || response.body() == null) {
                            callback.tts(null);
                        } else {
                            if (Objects.requireNonNull(response.header("Content-Type")).startsWith("audio/")) {
                                callback.tts(response.body().bytes());
                            } else {
                                if (logger.isInfoEnabled()) {
                                    logger.info("语音合成：{}", response.body().string());
                                }
                                callback.tts(null);
                            }
                        }
                    }

                    @Override
                    public void onFailure(Call call, IOException e) {
                        if (logger.isErrorEnabled()) {
                            logger.error("语音合成：{}", e, e);
                        }
                        callback.tts(null);
                    }
                });
            }
        });
    }

    interface Callback {
        /**
         * 获取语音合成结果
         *
         * @param buffer 语音
         */
        void tts(byte[] buffer);
    }

    enum Per {
        PER0("0", "度小美"),
        PER1("1", "度小宇"),
        PER3("3", "度逍遥"),
        PER4("4", "度丫丫");
        final String key;
        final String value;

        Per(String key, String value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return value;
        }
    }

    enum Aue {
        MP3("3", "mp3"),
        PCM16("4", "pcm-16k"),
        PCM8("5", "pcm-8k"),
        WAV("6", "wav");
        final String key;
        final String value;

        Aue(String key, String value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {
            return value;
        }
    }
}
